package com.liuqi.iot.collector.parser;

import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.liuqi.iot.bean.dto.GatewayDTO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 原始工况数据解析器
 *
 * @author  LiuQi 2025/3/28-8:28
 * @version V1.0
 **/
@Component
@Slf4j
public class OriginDataParser {
    /**
     * 原始数据解析
     * 不同厂商或不同客户上传过来的设备数据格式可能不一样，本方法根据传过来的数据自动做一层解析，适配不同输入数据格式
     * 目前主要适配的格式：
     * 1. {a: 1, b: 2, c: 3, timestamp: ...}
     * 2. {timestamp: ..., values: {...}}
     * 3. {timestamp: ..., properties: {...}}
     * 4. {deviceCode: {a: 1, b: 2, c: 3, timestamp: ...}}
     * 5. {deviceCode: {timestamp: ..., values: {...}}}
     * 6. {deviceCode: {timestamp: ..., properties: {...}}}
     *
     * @param deviceCode 设备编码，从主题中解析得到
     * @param obj        接收到的对象，类型为JSONObject或者JSONArray
     */
    public Map<String, List<JSONObject>> parse(GatewayDTO gateway, String deviceCode, Object obj) {
        Map<String, List<JSONObject>> map = new HashMap<>(16);
        if (obj instanceof JSONObject jsonObject) {
            if (jsonObject.containsKey("values")) {
                // 处理情况2
                List<JSONObject> list = this.parseValues(gateway, jsonObject, deviceCode, jsonObject.get("values"));
                map.put(deviceCode, list);
                return map;
            } else if (jsonObject.containsKey("properties")) {
                // 处理情况3
                List<JSONObject> list = this.parseValues(gateway, jsonObject, deviceCode, jsonObject.get("properties"));
                map.put(deviceCode, list);
                return map;
            } else if (existsTsField(gateway, jsonObject) || StringUtils.isNotBlank(deviceCode)) {
                // 处理情况1，从主题中解析到的设备编号不为空时，也是情况1
                List<JSONObject> list = this.parseValues(gateway, jsonObject, deviceCode, jsonObject);
                map.put(deviceCode, list);
                return map;
            } else {
                // 情况5、6
                return this.parseValuesForMultiDevice(gateway, jsonObject);
            }
        } else {
            JSONArray array = (JSONArray) obj;
            for (int i = 0; i < array.size(); i++) {
                JSONObject jsonObject = array.getJSONObject(i);
                map.putAll(this.parse(gateway, deviceCode, jsonObject));
            }
            return map;
        }
    }

    /**
     * 解析多设备的情况
     */
    private Map<String, List<JSONObject>> parseValuesForMultiDevice(GatewayDTO gateway, JSONObject jsonObject) {
        // 这里会有一种情况，情况1中没有上传时间辍字段，也会进到这里，需要特殊处理；
        // 这种情况与多设备的情况主要是多设备的子元素是对象，而情况1的子元素是直接值；
        Map<String, List<JSONObject>> map = new HashMap<>(16);
        jsonObject.keySet().forEach(deviceCode -> {
            JSONObject obj = jsonObject.getJSONObject(deviceCode);
            Map<String, List<JSONObject>> subList = this.parse(gateway, deviceCode, obj);
            map.putAll(subList);
        });

        return map;
    }

    /**
     * 判断对象中是否存在时间辍字段
     */
    private boolean existsTsField(GatewayDTO gateway, JSONObject obj) {
        String tsField = MapUtils.getString(gateway.getMetadata(), "tsField");
        if (!StringUtils.isBlank(tsField)) {
            return obj.containsKey(tsField);
        }

        return obj.containsKey("timestamp") || obj.containsKey("ts");
    }

    /**
     * 从对象中解析数据
     */
    private List<JSONObject> parseValues(GatewayDTO gateway, JSONObject origin, String deviceCode, Object values) {
        long ts = this.parseTimestamp(gateway, origin);

        // 目前只处理数据是对象的情况
        List<JSONObject> dataList = new ArrayList<>(16);
        if (values instanceof JSONObject jsonObject) {
            jsonObject.put("__ts", ts);
            jsonObject.put("__gatewayId", gateway.getId());
            jsonObject.put("__deviceCode", deviceCode);
            dataList.add(jsonObject);
        } else {
            log.warn("不支持的数据格式");
        }

        return dataList;
    }

    /**
     * 解析上云时间
     */
    private Long parseTimestamp(GatewayDTO gateway, JSONObject obj) {
        String tsField = MapUtils.getString(gateway.getMetadata(), "tsField", "timestamp");
        Object timestampObj = obj.get(tsField);
        if (null == timestampObj) {
            return LocalDateTime.now().toInstant(ZoneOffset.ofHours(8)).toEpochMilli();
        }

        if (timestampObj instanceof Long l) {
            return l;
        } else {
            // 字符串
            String str = timestampObj.toString();
            DateTimeFormatter formatter;
            if (str.contains(".")) {
                formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS");
            } else {
                formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
            }

            return LocalDateTime.parse(timestampObj.toString(), formatter).toInstant(ZoneOffset.ofHours(8)).toEpochMilli();
        }
    }
}
